package com.gitee.base.modules;

import com.gitee.base.utils.JsonVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.dao.DataAccessException;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.multipart.MaxUploadSizeExceededException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolationException;
import java.util.stream.Stream;

import static java.util.stream.Collectors.joining;

/**
 * 异常处理
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 处理数据库操作异常
     * @param dae
     * @return
     */
    @ExceptionHandler(DataAccessException.class)
    public JsonVo handlerDataAccessException(DataAccessException dae){
        log.error(dae.getMessage(),dae);
        return JsonVo.fail(500,"系统异常");
    }

    /**
     * 处理对象参数校验异常(非RequestBody对象参数)
     * @param be
     * @return
     */
    @ExceptionHandler(BindException.class)
    public JsonVo handlerBindException(BindException be){
        final String message = be.getBindingResult().getFieldErrors().stream().map(FieldError::getDefaultMessage).collect(joining(";  "));
        return JsonVo.badRequestErr(message);
    }

    /**
     * 处理非对象类型参数校验异常
     * @param cve
     * @return
     */
    @ExceptionHandler(ConstraintViolationException.class)
    public JsonVo handlerConstraintViolationException(ConstraintViolationException cve){
        String message = Stream.of(cve.getMessage().split(",")).flatMap(m -> Stream.of(m.split("\\."))).filter(m -> m.indexOf(":")>0).collect(joining(","));
//        String message = cve.getConstraintViolations().stream().map(ConstraintViolation::getMessage).collect(joining(";  "));
        return JsonVo.badRequestErr(message);
    }

    /**
     * 处理RequestBody修饰的对象参数校验异常
     * @param manve
     * @return
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public JsonVo handlerMethodArgumentNotValidException(MethodArgumentNotValidException manve){
        String message = manve.getBindingResult().getFieldErrors().stream().map(FieldError::getDefaultMessage).collect(joining(";  "));
        return JsonVo.badRequestErr(message);
    }

    /**
     * 处理登录异常
     * <b>已经在登录方法中拦截</b>
     * @param ae
     * @return
     */
    @Deprecated
    @ExceptionHandler(AuthenticationException.class)
    public JsonVo handlerAuthenticationException(AuthenticationException ae){
        return JsonVo.fail(500,ae.getMessage());
    }

    /**
     * 处理认证异常（如：没有菜单权限，访问了菜单）
     * @param request
     * @param response
     * @param uae
     * @return
     */
    @ExceptionHandler(UnauthorizedException.class)
    public JsonVo handlerUnauthorizedException(HttpServletRequest request, HttpServletResponse response, UnauthorizedException uae){
        return JsonVo.fail(403,"您没有权限操作此页面");
    }

    @ExceptionHandler(MaxUploadSizeExceededException.class)
    public JsonVo handlerMaxUploadSizeExceededException(MaxUploadSizeExceededException ex){
        log.error(ex.getMessage(),ex);
        return JsonVo.fail(500,"图片大小超过限制");
    }

    /**
     * 处理上述异常外所有的异常
     * @param dae
     * @return
     */
    @ExceptionHandler(Exception.class)
    public JsonVo handlerException(Exception dae){
        log.error(dae.getMessage(),dae);
        return JsonVo.fail(500,"系统繁忙，请稍后重试");
    }
}
